package com.shareware.common.utils

import com.shareware.common.DEFAULT

/**
 * desc: 功能描述
 * email: mobiledeveloper@qq.com
 */

fun reflectPublicField(instance: Any, fieldName: String): Any? {
    return try {
        val clazz = Class.forName(instance.javaClass.name)
        clazz.getField(fieldName).get(instance)
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
        null
    }
}

fun reflectPrivateField(instance: Any, fieldName: String): Any? {
    return try {
        val clazz = Class.forName(instance.javaClass.name)
        val field = clazz.getDeclaredField(fieldName)
        field.isAccessible = true
        field.get(instance)
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
        null
    }
}

fun reflectPublicField(instance: Any, fieldName: String, any: Any?) {
    try {
        val clazz = Class.forName(instance.javaClass.name)
        val field = clazz.getField(fieldName)
        field.set(instance, any)
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
    }
}

fun reflectPrivateField(instance: Any, fieldName: String, any: Any?) {
    try {
        val clazz = Class.forName(instance.javaClass.name)
        val field = clazz.getDeclaredField(fieldName)
        field.isAccessible = true
        field.set(instance, any)
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
    }
}

fun reflectPublicStaticField(clazz: Class<*>?, fieldName: String): Any? {
    if (clazz == null) {
        return null
    }
    return try {
        clazz.getField(fieldName).get(null)
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
        null
    }
}

fun reflectPublicStaticField(clazz: Class<*>?, fieldName: String, any: Any?) {
    if (clazz == null) {
        return
    }
    try {
        val field = clazz.getField(fieldName)
        field.isAccessible = true
        field.set(null, any)
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
    }
}

fun reflectPrivateStaticField(clazz: Class<*>?, fieldName: String): Any? {
    if (clazz == null) {
        return null
    }
    return try {
        val field = clazz.getDeclaredField(fieldName)
        field.isAccessible = true
        field.get(null)
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
    }
}

fun reflectPrivateStaticField(clazz: Class<*>?, fieldName: String, any: Any?) {
    if (clazz == null) {
        return
    }
    try {
        val field = clazz.getDeclaredField(fieldName)
        field.isAccessible = true
        field.set(null, any)
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
    }
}

/**
 * getMethod获取子类和其父类Public修饰的方法
 * getDeclaredMethod获取当前类所有方法
 */
fun reflectPublicMethod(
    instance: Any,
    methodName: String,
    methodParamsClasses: Array<Class<*>>? = null,
    methodParams: Array<Any>? = null
): Any? {
    return try {
        val clazz = Class.forName(instance.javaClass.name)
        if (methodParamsClasses.isNullOrEmpty() || methodParams.isNullOrEmpty()) {
            val method = clazz.getMethod(methodName)
            method.invoke(instance)
        } else {
            val method = clazz.getMethod(methodName, *methodParamsClasses)
            method.invoke(instance, *methodParams)
        }
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
        null
    }
}

fun reflectPrivateMethod(
    instance: Any,
    methodName: String,
    methodParamsClasses: Array<Class<*>>? = null,
    methodParams: Array<Any>? = null
): Any? {
    return try {
        val clazz = Class.forName(instance.javaClass.name)
        if (methodParamsClasses.isNullOrEmpty() || methodParams.isNullOrEmpty()) {
            val method = clazz.getDeclaredMethod(methodName)
            method.isAccessible = true
            method.invoke(instance)
        } else {
            val method = clazz.getDeclaredMethod(methodName, *methodParamsClasses)
            method.isAccessible = true
            method.invoke(instance, *methodParams)
        }
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
        null
    }
}

fun reflectPublicStaticMethod(
    className: String,
    methodName: String,
    methodParamsClasses: Array<Class<*>>? = null,
    methodParams: Array<Any>? = null
): Any? {
    if (className.isEmpty()) {
        return null
    }
    return reflectPublicStaticMethod(
        try {
            Class.forName(className)
        } catch (ignore: Exception) {
            null
        }, methodName, methodParamsClasses, methodParams
    )
}

fun reflectPublicStaticMethod(
    clazz: Class<*>?,
    methodName: String,
    methodParamsClasses: Array<Class<*>>? = null,
    methodParams: Array<Any>? = null
): Any? {
    if (clazz == null) {
        return null
    }
    return try {
        if (methodParamsClasses.isNullOrEmpty() || methodParams.isNullOrEmpty()) {
            val method = clazz.getMethod(methodName)
            method.invoke(null)
        } else {
            val method = clazz.getMethod(methodName, *methodParamsClasses)
            method.invoke(null, *methodParams)
        }
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
        null
    }
}

fun reflectPrivateStaticMethod(
    className: String,
    methodName: String,
    methodParamsClasses: Array<Class<*>>? = null,
    methodParams: Array<Any>? = null
): Any? {
    if (className.isEmpty()) {
        return null
    }
    return reflectPrivateStaticMethod(
        try {
            Class.forName(className)
        } catch (ignore: Exception) {
            null
        }, methodName, methodParamsClasses, methodParams
    )
}

fun reflectPrivateStaticMethod(
    clazz: Class<*>?,
    methodName: String,
    methodParamsClasses: Array<Class<*>>? = null,
    methodParams: Array<Any>? = null
): Any? {
    if (clazz == null) {
        return null
    }
    return try {
        if (methodParamsClasses.isNullOrEmpty() || methodParams.isNullOrEmpty()) {
            val method = clazz.getDeclaredMethod(methodName)
            method.isAccessible = true
            method.invoke(null)
        } else {
            val method = clazz.getDeclaredMethod(methodName, *methodParamsClasses)
            method.isAccessible = true
            method.invoke(null, *methodParams)
        }
    } catch (ex: Exception) {
        logStackTrace(DEFAULT, ex)
        null
    }
}